using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.VisualBasic;
using System.Threading;
using System.Diagnostics;
using System.IO;
using System.Globalization;
using System.Configuration;
using System.Reflection;

namespace vXCopy
{
	public delegate int DelegateAddItem(object sender, FileToProcess e);
	public delegate int DelegateEditItem(object sender, FileToProcess e);
	public delegate int DelegateDeleteItem(object sender, FileToProcess e);

	public delegate int DelegateDisplayItem(object sender, FileToProcess e);

	public delegate int DelegateFolderFound(string File);
	public delegate int DelegateFileFound(string File, Int32 FilesFound);

	public delegate int DelegateGetRowIndex(Int32 RowID);



	public partial class frmFileProcess : Form
	{
		private dsFavoritePath.FavoritePathDataTable ofromPath = null;
		private dsFavoritePath.FavoritePathDataTable odestPath = null;

		private CurrencyManager currencyManager = null;
		private Int32 nSearchFiles = 0;
		private Int32 nSearchFolders = 0;

		static Int32 LastRowID = 0;

		internal DelegateAddItem delAddItem = null;
		internal DelegateEditItem delEditItem = null;
		internal DelegateDeleteItem delDeleteItem = null;

		internal DelegateDisplayItem delDisplayItem = null;
		internal DelegateGetRowIndex delGetRowIndex = null;

		internal DelegateFolderFound delFolderFound = null;
		internal DelegateFileFound delFileFound = null;

		CmdLineSettingLib cmdLineSettingLib = null;

		static AutoResetEvent _autoEvent = new AutoResetEvent(false);
		internal System.Timers.Timer mainTimer = null;
		internal System.Timers.Timer copyTimer = null;


		public event EventHandler EventSearchDone;
		public event EventHandler EventCopyDone;
		private long _running = 0;
		private int nOffset = 0;
		private double nFileToCopy = 0;
		string tmpPath = "";

		internal bool bGettingRow = false;
		internal bool bSearchDone = false;
		internal bool bFilesToCopy = false;
		internal bool bBatchMode = false;
		internal bool bCopyTimerRunning = false;
		internal bool bFileOpRunning = false;
		internal bool bProcessRunning = false;
		internal bool bStopProcess = false;
		internal bool bUserStopProject = false;

		internal Thread searchThread = null;

		internal long mThreadCountNumber = 0;
		

		internal DirectoryInfo ofromFolder;
		internal DirectoryInfo oDestFolder;

		internal FileToProcessList fileToProcessList = null;

		readonly object stateLock = new object();

		internal List<ProcessFileCopy> processFileCopyList = null;


		public frmFileProcess(string[] args)
		{
			//
			InitializeComponent();

			statusStripMain.Dock = DockStyle.Bottom;
			tsMain.Dock = DockStyle.Top;
			dtFile.Dock = DockStyle.Fill;
			tbLayoutPanelMain.Dock = DockStyle.Fill;
			cboSourcePath.Dock = DockStyle.Fill;
			dtFile.Dock = DockStyle.Fill;

			delAddItem = new DelegateAddItem(this.AddFileToList);
			delEditItem = new DelegateEditItem(this.EditFileToList);
			delDeleteItem = new DelegateDeleteItem(this.DeleteFileToList);

			delDisplayItem = new DelegateDisplayItem(this.DisplayItem);
			delGetRowIndex = new DelegateGetRowIndex(this.GetRowIndex);

			delFolderFound = new DelegateFolderFound(this.FolderFound);
			delFileFound = new DelegateFileFound(this.FileFound);

			cmdLineSettingLib = new CmdLineSettingLib();

			//mainApp.Start();
			this.Top = 0;
			this.Left = 0;
			this.Width = 1024;
			this.Height = 800;

			mainTimer = new System.Timers.Timer();
			mainTimer.Enabled = false;
			mainTimer.Interval = 500;
			mainTimer.Elapsed += new System.Timers.ElapsedEventHandler(mainTimer_Elapsed);

			copyTimer = new System.Timers.Timer();
			copyTimer.Interval = 250;
			copyTimer.Elapsed += new System.Timers.ElapsedEventHandler(copyTimer_Elapsed);

			this.cmdLineSettingLib.copySubFolder = false;

			
			bBatchMode = (args.Length != 0);

			if (args.Length == 0)
			{
#if(!DEBUG)
				this.cmdLineSettingLib.fromFolder = @"L:\Download\Microsoft\DotNet";
				this.cmdLineSettingLib.destFolder = @"N:\Download\Microsoft\DotNet";
				this.cmdLineSettingLib.MaxThreads = 8;
				this.cmdLineSettingLib.copySubFolder = false;

				try
				{
					DirectoryInfo dir = new DirectoryInfo(this.cmdLineSettingLib.destFolder);
					dir.Delete(true);
				}
				catch (Exception)
				{ }
#endif

			}

			else
			{
				// Check to see if the user passed in a filename 
				if (args.Length < 2)
				{
					DisplayUsage();
					this.Close();
				}
				if (args.Length > 8)
				{
					DisplayUsage();
					this.Close(); ;
				}

				if (args[0] == "/?")
				{
					DisplayUsage();
					this.Close();
				}

				if (args.Length >= 3)
				{

					this.cmdLineSettingLib.fromFolder = args[0];
					//
					if (!UtilLibrary.CheckFolder(this.cmdLineSettingLib.fromFolder))
					{
						MessageBox.Show(string.Format("Folder [{0}] doesn't exist", this.cmdLineSettingLib.fromFolder));
						Debug.WriteLine(string.Format("Folder [{0}] doesn't exist", this.cmdLineSettingLib.fromFolder));
						this.Close();
					}
					//
					this.cmdLineSettingLib.destFolder = args[1];


					try
					{


						foreach (string sarg in args)
						{
							
							string _sarg = sarg.Trim().ToUpper();
							
							Debug.WriteLine("sarg: " + _sarg);

							if (_sarg.Contains("T"))
							{
								this.cmdLineSettingLib.MaxThreads = Int32.Parse(sarg.Replace("/T", "").Replace("/t", ""));
								if (this.cmdLineSettingLib.MaxThreads < 1 || this.cmdLineSettingLib.MaxThreads > 15)
								{
									DisplayUsage();
									this.Close();
								}
							}

							if (_sarg.Contains("/XF"))
							{
								this.cmdLineSettingLib.ExcludeFiles = _sarg.Replace("/XF", "").Replace("/xf", "");
							}

							if (_sarg.Contains("/XD"))
							{
								this.cmdLineSettingLib.ExcludeFolders = _sarg.Replace("/XD", "").Replace("/xd", "");
							}

							if (_sarg.Contains("/IF"))
							{
								this.cmdLineSettingLib.IncludeFiles = _sarg.Replace("/IF", "").Replace("/if", "");
							}

							if (_sarg.Contains("/ID"))
							{
								this.cmdLineSettingLib.IncludeFolders = _sarg.Replace("/ID", "").Replace("/id", "");
							}

							if (_sarg.Contains("/S"))
							{
								this.cmdLineSettingLib.copySubFolder = true;
							}

						}

					}

					catch (Exception ex)
					{
						Debug.WriteLine("ERROR:" + ex.Message);
					}
				}

				if (args[2].ToUpper().Contains("/S"))
				{
					this.cmdLineSettingLib.copySubFolder = true;
				}
				
				if (args[3].ToUpper().Contains("/S"))
				{
					
					this.cmdLineSettingLib.MaxThreads = Int32.Parse(args[2]);
					if (this.cmdLineSettingLib.MaxThreads < 1 || this.cmdLineSettingLib.MaxThreads > 15)
					{
						DisplayUsage();
						this.Close();
					}

					this.cmdLineSettingLib.copySubFolder = true;
				}

				if (!UtilLibrary.CheckCreateFolder(this.cmdLineSettingLib.destFolder, false))
				{
					MessageBox.Show("Process interrupted by User");
					this.Close(); 
				}
			}

			currencyManager = (CurrencyManager)this.BindingContext[this.dsFile.vXTable];
			currencyManager.DataError += new BindingManagerDataErrorEventHandler(currencyManager_DataError);
			currencyManager.ItemChanged += new ItemChangedEventHandler(currencyManager_ItemChanged);
			currencyManager.ListChanged += new ListChangedEventHandler(currencyManager_ListChanged);
			currencyManager.MetaDataChanged += new EventHandler(currencyManager_MetaDataChanged);
			currencyManager.PositionChanged += new EventHandler(currencyManager_PositionChanged);

			// Autosize the columns for dtProcessFile.
			this.dtFile.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;

			this.tsStatusImage.Width = 0;

			SetDataGridView();


			tsMainButtonStop.Enabled = true;
			tsMainButtonStop.Enabled = false;
			tsStatusSessionStart.Text = DateTime.Now.ToString("G");
			tsStatusSessionEnd.Text = DateTime.Now.ToString("G");

			Version version = Assembly.GetExecutingAssembly().GetName().Version;
			this.Text = String.Format("vXCopy - version {0}.{1}.{2}.{3} - Copyrights 2005 - Vincent RITHNER - All Rights Reserved", version.Major, version.Minor, version.Build.ToString(), version.Revision);		

			this.Show();

			//Retrieve Xml Favorite Path 
			ofromPath = new dsFavoritePath.FavoritePathDataTable();
			odestPath = new dsFavoritePath.FavoritePathDataTable();
			try
			{
				ofromPath.ReadXml("FavoriteFromPath.xml");
				odestPath.ReadXml("FavoriteDestPath.xml");
				//Bind data to cbo
				cboSourcePath.DataSource = ofromPath;
				cboSourcePath.DisplayMember = "Path";
				cboDestPath.DataSource = odestPath;
				cboDestPath.DisplayMember = "Path";
			}
			catch (Exception)
			{ }

			if (args.Length != 0)
			{
				this.cboSourcePath.Text = this.cmdLineSettingLib.fromFolder;
				this.dtFile.Text = this.cmdLineSettingLib.destFolder;

				this.txtIncludeFolders.Text = this.cmdLineSettingLib.IncludeFolders;
				this.txtIncludeFiles.Text = this.cmdLineSettingLib.IncludeFiles;
				this.txtExcludeFolders.Text = this.cmdLineSettingLib.ExcludeFolders;
				this.txtExcludeFiles.Text = this.cmdLineSettingLib.ExcludeFiles;
				this.numUpDownThread.Value = decimal.Parse(this.cmdLineSettingLib.MaxThreads.ToString());
				this.chkCopySubFolder.Checked = this.cmdLineSettingLib.copySubFolder;
			}

			Application.DoEvents();

			this.Refresh();
			this.Select();

			mainTimer.Start();



			//Check for Batch mode and Start if apply
			if (args.Length != 0)
				this.Start();

		}

		void SetDataGridView()
		{
			dtFile.Columns[0].Width = 40;
			dtFile.Columns[0].Visible = false;

			//Source Folder
			dtFile.Columns[1].Width = 230;
			dtFile.Columns[1].DisplayIndex = 0;

			//File Name
			dtFile.Columns[2].Width = 150;
			dtFile.Columns[2].DisplayIndex = 1;

			//Status
			dtFile.Columns[3].Width = 150;
			dtFile.Columns[3].DisplayIndex = 2;
			dtFile.Columns[3].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;

			//Size
			dtFile.Columns[4].Width = 70;
			dtFile.Columns[4].DisplayIndex = 3;
			dtFile.Columns[4].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;

			//Date
			dtFile.Columns[5].Width = 140;
			dtFile.Columns[5].DisplayIndex = 4;
			dtFile.Columns[5].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
			dtFile.Columns[5].DefaultCellStyle.Format = "G";

			dtFile.Columns[6].Width = 200;
			dtFile.Columns[6].DisplayIndex = 5;

		}

		/// <summary>
		/// 
		/// </summary>
		private void SetControlsStatus()
		{
			try
			{
				Debug.WriteLine("bProcessRunning: " + bProcessRunning.ToString());
				Debug.WriteLine("bStopProcess: " + bStopProcess.ToString());

				tsStatusImage.Visible = bProcessRunning;

				this.cboSourcePath.Enabled = !bProcessRunning;
				this.cboDestPath.Enabled = !bProcessRunning;

				this.tbLayoutPanelInclude.Enabled = !bProcessRunning;
				this.tbLayoutPanelExclude.Enabled = !bProcessRunning;
				this.chkCopySubFolder.Enabled = !bProcessRunning;

				if (bProcessRunning && this.tsStatusImage.Image == null)
				{
					this.tsStatusImage.Width = 50;
					this.tsStatusImage.Image = (Image)vXCopy.Properties.Resources.status_anim;
				}

				if (!bProcessRunning && this.tsStatusImage.Image != null)
				{
					this.tsStatusImage.Width = 0;
					this.tsStatusImage.Image = null;
				}

				tsMainButtonStart.Enabled = !bProcessRunning;
				tsMainButtonStop.Enabled = bProcessRunning;

				Debug.WriteLine("!bProcessRunning && this.bBatchMode && !bStopProcess: " + bProcessRunning.ToString() + "-" + this.bBatchMode.ToString() + "-" + bStopProcess.ToString());

				//Check if we must quit application now
				if (!bProcessRunning && this.bBatchMode && !bUserStopProject)
				{
					this.Stop();
					this.Close();
				}
			}

			catch (Exception ex)
			{

				Debug.WriteLine(ex.Message);
			}
		}

		void currencyManager_PositionChanged(object sender, EventArgs e)
		{
			try
			{
				if (currencyManager.Position > dtFile.Rows.Count - 1 || dtFile.Rows.Count == 0)
					currencyManager.Position = -1;
			}
			catch (Exception ex)
			{
				Debug.WriteLine("!!!!ERROR---> CurrencyManager::Error:" + ex.Message);
			}
		}

		void currencyManager_MetaDataChanged(object sender, EventArgs e)
		{
			try
			{
			}
			catch (Exception ex)
			{
				Debug.WriteLine("!!!!ERROR---> CurrencyManager::Error:" + ex.Message);
			}
		}

		void currencyManager_ListChanged(object sender, ListChangedEventArgs e)
		{
			try
			{
				if (currencyManager.Position > dtFile.Rows.Count - 1 || dtFile.Rows.Count == 0)
					currencyManager.Position = -1;

			}
			catch (Exception ex)
			{
				Debug.WriteLine("!!!!ERROR---> CurrencyManager::Error:" + ex.Message);
			}
		}

		void currencyManager_ItemChanged(object sender, ItemChangedEventArgs e)
		{
			try
			{
				if (currencyManager.Position > dtFile.Rows.Count - 1 || dtFile.Rows.Count == 0)
					currencyManager.Position = -1;

			}
			catch (Exception ex)
			{
				Debug.WriteLine("!!!!ERROR---> CurrencyManager::Error:" + ex.Message);
			}
		}

		void currencyManager_DataError(object sender, BindingManagerDataErrorEventArgs e)
		{
			try
			{
			}
			catch (Exception ex)
			{
				Debug.WriteLine("!!!!ERROR---> CurrencyManager::Error:" + ex.Message);
			}
		}

		internal int GetRowIndex(Int32 RowID)
		{
			int nIndex = -1;
			try
			{

				foreach (DataGridViewRow oRow in dtFile.Rows)
				{
					if ((int)oRow.Cells[0].Value == RowID)
					{
						nIndex = oRow.Index;
						break;
					}
				}

				//Debug.WriteLine("///////////////////////////////////---> GetRowIndex::I:oItem.Tag:RowID " + nIndex.ToString() + "==" + RowID.ToString());

				return nIndex;

			}
			catch (Exception ex)
			{
				Debug.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!ERROR!!!!! GetRowIndex: " + nIndex.ToString() + " --> " + ex.Message);
				return -1;
			}
			finally
			{
				//bGettingRow = false;
			}
		}


		internal int DisplayItem(object sender, FileToProcess e)
		{
			this.txtExcludeFolders.Text = mThreadCountNumber.ToString();

			return 0;
		}

		internal void fileToCopy_EventfileProcessStatusToProcess(object sender, FileToProcess e)
		{
			this.delEditItem.Invoke(sender, e);
		}

		internal void fileToCopy_EventfileToProcess(object sender, FileToProcess e)
		{
			this.delEditItem.Invoke(sender, e);
		}

		internal int EditFileToList(object sender, FileToProcess e)
		{

			bGettingRow = true;
			//Debug.WriteLine("####################################-0--->frmFileProcess::EditFileToList::e.RowID: " + e.RowID.ToString());

			if (dtFile.Rows.Count == 0)
				return 0;

			int nRowIndex = -1;

			try
			{

				Monitor.Enter(stateLock);
				nRowIndex = delGetRowIndex(e.RowID);
				Monitor.Exit(stateLock);

				if (nRowIndex == -1 || nRowIndex >= dtFile.Rows.Count)
					return -1;


				DataGridViewRow oRow = null;
				try
				{
					oRow = dtFile.Rows[nRowIndex];
				}
				catch (Exception)
				{ }

				//Debug.WriteLine("####################################-2--->frmFileProcess::EditFileToList::e.RowID: " + e.RowID.ToString());

				//Monitor.Enter(stateLock);
				//oRow.Name = e.oFileSourceInfo.Name;
				//oRow.Size = double.Parse(e.oFileSourceInfo.Length.ToString());
				//oRow.Source_Folder = e.fromFolder;
				//oRow.Date_Last_Access = e.oFileSourceInfo.LastWriteTime;

				oRow.Cells[3].Value = e.ItemStatus;
				oRow.Cells[6].Value = e.ProcessStatus;

				//Monitor.Exit(stateLock);

				//Debug.WriteLine("####################################-3--->frmFileProcess::EditFileToList::e.RowID: " + e.RowID.ToString());

				Thread.Sleep(100);
			}

			catch (Exception ex)
			{
				Debug.WriteLine("frmFileProcess::EditFileToList: " + ex.Message);
			}
			finally
			{
				//this.Refresh();
				bGettingRow = false;
			}

			return 0;
		}

		internal void fileToCopy_EventErrorfileToProcess(object sender, FileToProcess e)
		{

		}


		internal void fileToCopy_EventfileCreatedToProcess(object sender, FileToProcess e)
		{
			this.delAddItem.Invoke(sender, e);
		}

		internal int AddFileToList(object sender, FileToProcess e)
		{
			try
			{

				dsFile.vXTableRow oRow = dsFile.vXTable.NewvXTableRow();

				//Monitor.Enter(stateLock);
				oRow.Name = e.oFileSourceInfo.Name;
				oRow.Status = e.ItemStatus;
				oRow.Size = double.Parse(e.oFileSourceInfo.Length.ToString());
				oRow.Source_Folder = e.fromFolder;
				oRow.Date_Last_Access = e.oFileSourceInfo.LastWriteTime;
				oRow.Percent = e.ProcessStatus;

				Monitor.Enter(stateLock);
				LastRowID++;
				oRow.RowID = LastRowID;
				e.RowID = oRow.RowID;
				Monitor.Exit(stateLock);

				object[] row = new object[] { oRow.RowID, oRow.Source_Folder, oRow.Name, oRow.Status, oRow.Size, oRow.Date_Last_Access, oRow.Percent };
				dtFile.Rows.Add(row);

				dtFile.Sort(dtFile.Columns[4], ListSortDirection.Descending);

				//Debug.WriteLine("---------------------------0--->frmFileProcess::AddFileToList::dsFile: " + dsFile.vXTable.Rows.Count.ToString());

			}
			catch (Exception ex)
			{
				Debug.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!frmFileProcess::AddFileToList: " + ex.Message);
			}
			finally
			{
				//this.Refresh();
				//Application.DoEvents();
			}
			return 0;
		}


		internal void fileToCopy_fileCompleted(object sender, FileToProcess e)
		{
			try
			{
				this.delDeleteItem.Invoke(sender, e);
			}
			catch (Exception ex)
			{
				Debug.WriteLine("######### ----->frmFileProcess::fileToCopy_fileCompleted::Error:" + ex.Message);
			}
			finally
			{
			}

		}

		internal int DeleteFileToList(object sender, FileToProcess e)
		{
			int nRowIndex = -1;

			try
			{

				Monitor.Enter(stateLock);
				nRowIndex = delGetRowIndex(e.RowID);
				Monitor.Exit(stateLock);

				if (nRowIndex == -1 || nRowIndex >= dtFile.Rows.Count)
					return -1;


				DataGridViewRow oRow = dtFile.Rows[nRowIndex];


				dtFile.Rows.Remove(oRow);

				fileToProcessList.FilesList.Remove(e);

				Monitor.Enter(stateLock);
				mThreadCountNumber = mThreadCountNumber - 1;
				nFileToCopy = nFileToCopy - 1;
				Monitor.Exit(stateLock);

				//((ProcessFileCopy)sender).copyFileThread.Join();
				//((ProcessFileCopy)sender).copyFileThread.Abort(); 
			}
			catch (Exception ex)
			{
				Debug.WriteLine("######### ----->frmFileProcess::DeleteFileToList::Error:" + ex.Message);

			}
			finally
			{
				//    Monitor.Enter(this);

				//    Monitor.Exit(stateLock);
				//Debug.WriteLine("######### ----->frmFileProcess::fileToCopy_fileCompleted::mThreadCountNumber:" + mThreadCountNumber.ToString());

			}
			return 0;
		}

		private static void DisplayUsage()
		{
			// User did not provide enough parameters. 
			// Display usage: 
			StringBuilder sb = new StringBuilder();

			sb.Append("-----------------------------------------------------------------------------------");
			sb.Append("\n");
			sb.Append("vxCopy - Draft 0.1 - (Copyright VRDotNET 2005 - All Rights Reserved)");
			sb.Append("\n");
			sb.Append("-----------------------------------------------------------------------------------");
			sb.Append("\n\n");
			sb.Append("Copy Folder/Files Recursively in MultiTreads mode");
			sb.Append("\n\n");
			sb.Append("vxCopy FromFolder DestFolder [Thread #]");
			sb.Append("Usage: vxCopy FromFolder DestFolder /T6 /S /IF*.* /ID*.* /XF*64*.* /XDAMD");
			sb.Append("\n");
			sb.Append("Thread # (Min= 1 / Max=15)-(Default= 4");
			sb.Append("\n\n");
			MessageBox.Show(sb.ToString());
		}

		private void StopSearch()
		{
			if (this != null)
				this.Stop();


		}


		private int FolderFound(string Folder)
		{
			try
			{

				tsStatusStatFolders.Text = "Folders:" + nSearchFolders.ToString();

				return 0;
			}
			catch (Exception ex)
			{
				Debug.WriteLine("DirFound: " + ex.Message);
				return -1;
			}
		}

		private int FileFound(string File, Int32 FilesFound)
		{
			try
			{

				tsStatusStatFiles.Text = "Files:" + FilesFound.ToString();
				return 0;
			}
			catch (Exception ex)
			{
				Debug.WriteLine("FileFound: " + ex.Message);
				return -1;
			}
		}

		void delSearchDone(object sender, EventArgs e)
		{
			try
			{
				this.SearchDone(sender, e);
			}
			catch (InvalidOperationException) //user closed the form, so the this handle is no longer valid
			{
			}

		}

		void delCopyDone(object sender, EventArgs e)
		{
			try
			{
				this.CopyDone(sender, e);
			}
			catch (InvalidOperationException) //user closed the form, so the this handle is no longer valid
			{
			}

		}
		void SearchDone(object sender, EventArgs e)
		{
			bSearchDone = true;
			Debug.WriteLine("Searched All Files EventSearchDone....");
			Debug.WriteLine("Ready.");
		}

		void CopyDone(object sender, EventArgs e)
		{
			Debug.WriteLine("Copied All Files EventCopyDone....");
			Debug.WriteLine("Ready.");
			this.Stop();
		}

		public void Start()
		{
			Debug.WriteLine("Process Started....");
			tsStatusMessage.Text = "Process Started...";
			tsStatusSessionStart.Text = DateTime.Now.ToString("G");
			tsStatusSessionEnd.Text = DateTime.Now.ToString("G");

			//Save settings in user profile
			vXCopy.Properties.Settings p = Properties.Settings.Default;
			p.SourcePath = this.cboSourcePath.Text;
			p.DestPath = this.dtFile.Text;
			p.ThreadNumber = decimal.Parse(numUpDownThread.Value.ToString());
			p.CopySubFolder = this.chkCopySubFolder.Checked;
			p.IncludeFiles = this.txtIncludeFiles.Text;
			p.IncludeFolders = this.txtIncludeFolders.Text;
			p.ExcludeFiles = this.txtExcludeFiles.Text;
			p.ExcludeFolders = this.txtExcludeFolders.Text;
			p.Save();

			//Save Path in FavoritePath Xml
			try
			{
				Debug.WriteLine("1");
				dsFavoritePath.FavoritePathRow rfrom = ofromPath.NewFavoritePathRow();
				Debug.WriteLine("2");
				DataRow rffrom = ofromPath.Rows.Find(cboSourcePath.Text);
				Debug.WriteLine("3");
				if (rffrom == null)
				{
					Debug.WriteLine("4");
					rfrom.Path = cboSourcePath.Text;
					BindingSource bfrom = (BindingSource)cboSourcePath.DataSource;
					int pos = bfrom.Find("Path", r.Path);
					Debug.WriteLine("5");
					ofromPath.Rows.Add(rfrom);
					cboSourcePath.SelectedIndex = posfrom;
				}

				Debug.WriteLine("6");
				dsFavoritePath.FavoritePathRow rdest = odestPath.NewFavoritePathRow();
				Debug.WriteLine("7");
				DataRow rfdest = odestPath.Rows.Find(cboSourcePath.Text);
				if (rfdest == null)
				{
					Debug.WriteLine("8");
					rdest.Path = cboDestPath.Text;
					Debug.WriteLine("9");
					int posdest = cboDestPath.SelectedIndex;
					odestPath.Rows.Add(rdest);
					Debug.WriteLine("10");
					cboDestPath.SelectedIndex = posdest;
				}

				ofromPath.WriteXml("FavoriteFromPath.xml");
				odestPath.WriteXml("FavoriteDestPath.xml");
			}
			catch (Exception ex)
			{
				Debug.WriteLine("Error:Can't save Xml file: " + ex.Message);
			}

			nSearchFolders = 0;
			nSearchFiles = 0;

			this.cmdLineSettingLib.fromFolder = p.SourcePath;
			this.cmdLineSettingLib.destFolder = p.DestPath;
			this.cmdLineSettingLib.MaxThreads = int.Parse(p.ThreadNumber.ToString());
			this.cmdLineSettingLib.copySubFolder = p.CopySubFolder;

			this.EventSearchDone += new EventHandler(this.delSearchDone);
			this.EventCopyDone += new EventHandler(this.delCopyDone);

			//Start copy
			bSearchDone = false;
			bFilesToCopy = false;
			bStopProcess = false;
			bProcessRunning = true;

			processFileCopyList = new List<ProcessFileCopy>();

			copyTimer.Enabled = true;

			this.mThreadCountNumber = 0;
			this._running = 1;

			///
			this.ProcessCopy();
		}

		public void Stop()
		{
			bStopProcess = true;
			bProcessRunning = false;

			tsStatusMessage.Text = "Process Stopped...";

			copyTimer.Stop();
			copyTimer.Enabled = false;

			if (System.Threading.Interlocked.Read(ref _running) > 0)
			{
				System.Threading.Interlocked.Exchange(ref _running, 0);
				_autoEvent.WaitOne();
				_running = 0;

				foreach (ProcessFileCopy oProcessFile in processFileCopyList)
				{
					if (oProcessFile != null)
					{
						if (oProcessFile.copyFileThread.IsAlive)
							oProcessFile.copyFileThread.Abort();

					}
				}
			}

			mThreadCountNumber = 0;
			tsStatusMessage.Text = " Ready";
			tsStatusSessionEnd.Text = DateTime.Now.ToString("G");

		}

		public bool ProcessCopy()
		{
			try
			{

				ofromFolder = new DirectoryInfo(this.cmdLineSettingLib.fromFolder);
				oDestFolder = new DirectoryInfo(this.cmdLineSettingLib.destFolder);

				if (!UtilLibrary.CheckFolder(ofromFolder))
				{
					Debug.WriteLine("Source Folder [{0}] doesn't exist !", this.cmdLineSettingLib.fromFolder);
					return false;
				}

				ProcessGetAllFiles();
				return true;
			}
			finally
			{
			}
		}



		/// <summary>
		/// mainTimer_Elapsed
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void mainTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
		{
			try
			{
				SetControlsStatus();

				Debug.WriteLine("----->frmFileProcess::mainTimer_Elapsed:mThreadCountNumber: " + mThreadCountNumber.ToString());

				if (bStopProcess)
					return;
				{
					if (System.Threading.Interlocked.Read(ref mThreadCountNumber) >= this.cmdLineSettingLib.MaxThreads)
					{
						Debug.WriteLine("----->frmFileProcess::mainTimer_Elapsed:Copy Timer Process Stopped...");
						copyTimer.Stop();

					}
					else
					{
						Debug.WriteLine("----->frmFileProcess::mainTimer_Elapsed:Copy Timer Process Resumed...");
						copyTimer.Start();
					}
					return;
				}
			}
			catch (Exception ex)
			{

				Debug.WriteLine("mainClass::mainTimer_Elapsed" + ex.Message);
			}
		}


		internal void ProcessGetAllFiles()
		{

			try
			{
				fileToProcessList = new FileToProcessList();

				//searchThread = new Thread(SearchFilesThread);

				System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(SearchFilesThread));

				//mainTimer.Start();

				//Thread.Sleep(500);

				//searchThread.Join();

			}

			catch (Exception ex)
			{
				Debug.WriteLine("ProcessGetAllFiles: " + ex.Message);
			}
			finally
			{

			}

		}

		private void SearchFilesThread(object State)
		{
			//GetAllFiles(this.ofromFolder.FullName, this.oDestFolder.FullName, true);
			GetAllFiles(this.cmdLineSettingLib.fromFolder, this.cmdLineSettingLib.destFolder, this.cmdLineSettingLib.copySubFolder);
		}

		void copyTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
		{
			try
			{
				Debug.WriteLine("#######----->frmFileProcess::copyTimer_Elapsed:mThreadCountNumber:" + (System.Threading.Interlocked.Read(ref mThreadCountNumber)));

				if (_running == 0 || bFileOpRunning || (System.Threading.Interlocked.Read(ref mThreadCountNumber) >= this.cmdLineSettingLib.MaxThreads))
					return;

				bFileOpRunning = true;


				if (fileToProcessList.FilesList.Count == 0)
				{
					if (bFilesToCopy && nFileToCopy == 0 || !bFilesToCopy && bSearchDone)
					{
						EventCopyDone(sender, e);
					}
					return;
				}
				else
				{
					bFilesToCopy = true;
				}

				if (System.Threading.Interlocked.Read(ref _running) > 0)
				{
					//Check if we must stop processing files
					if (this.bStopProcess)
					{
						copyTimer.Stop();
						copyTimer.Enabled = false;
						return;
					}
				}

				FileToProcess file = fileToProcessList.FilesList[0];

				ProcessFileCopy fileToCopy = new ProcessFileCopy(file, (int)mThreadCountNumber);

				fileToCopy.FileCompleted += new EventHandler<FileToProcess>(this.fileToCopy_fileCompleted);
				fileToCopy.EventfileCreatedToProcess += new EventHandler<FileToProcess>(this.fileToCopy_EventfileCreatedToProcess);
				fileToCopy.EventfileToProcess += new EventHandler<FileToProcess>(this.fileToCopy_EventfileToProcess);
				fileToCopy.EventfileErrorToProcess += new EventHandler<FileToProcess>(this.fileToCopy_EventErrorfileToProcess);
				fileToCopy.EventfileProcessStatusToProcess += new EventHandler<FileToProcess>(this.fileToCopy_EventfileProcessStatusToProcess);

				Monitor.Enter(stateLock);
				mThreadCountNumber++;
				Monitor.Exit(stateLock);

				processFileCopyList.Add(fileToCopy);
				nFileToCopy++;

				fileToCopy.StartCopy();

				Monitor.Enter(stateLock);
				fileToProcessList.FilesList.Remove(file);
				Monitor.Exit(stateLock);

				//Thread.Sleep(100);

			}

			catch (Exception ex)
			{

				Debug.WriteLine("frmFileProcess::copyTimer_Elapsed:Error: " + ex.Message);
			}
			finally
			{
				bFileOpRunning = false;
				_autoEvent.Set();
			}
		}

		/// <summary>
		/// This function retrieve all Files in the current Folder and sub-folder if apply
		/// </summary>
		/// <param name="fromDir"></param>
		/// <param name="destDir"></param>
		/// <param name="recursive"></param>
		void GetAllFiles(string fromDir, string destDir, bool recursive)
		{
			DateTimeFormatInfo dfi = new DateTimeFormatInfo();
			dfi.FullDateTimePattern = "dd/mm/yyyy -- " + dfi.ShortTimePattern;

			try
			{
				nOffset += 1;

				Thread.CurrentThread.Priority = ThreadPriority.Lowest;

				string[] _dirs = Directory.GetDirectories(fromDir);
				string[] _files = Directory.GetFiles(fromDir);

				if (!recursive)
				{
					delFolderFound.Invoke(fromDir);
				}
				else
				{
					//
					foreach (string subDir in _dirs)
					{
						if (System.Threading.Interlocked.Read(ref _running) > 0)
						{
							Monitor.Enter(stateLock);
							nSearchFolders++;
							Monitor.Exit(stateLock);

							delFolderFound.Invoke(subDir);

							///create the path to the directory in destdir
							tmpPath = Path.Combine(destDir, UtilLibrary.GetFileNameOnly(subDir));

							FileToProcess ofile = new FileToProcess();
							ofile.ItemStatus = "Crawling";
							ofile.ItemNumber = _dirs.Length;
							ofile.fromFolder = subDir;
							ofile.destFolder = tmpPath;
							ofile.IncludeFolders = txtIncludeFolders.Text.Trim();
							ofile.ExcludeFolders = txtExcludeFolders.Text.Trim();

							

							//Filter Folder
							if (!ofile.CheckToProcess())
								break;

							DirectoryInfo tmpDestFolder = new DirectoryInfo(tmpPath);

							//recursively call this function over and over again with each new dir.
							GetAllFiles(subDir, tmpDestFolder.FullName, recursive);

						}
						else
						{
							break;
						}
					}

				}

				foreach (string file in _files)
				{

					if (System.Threading.Interlocked.Read(ref _running) > 0)
					{

						//Check if we must stop processing files
						if (this.bStopProcess)
						{
							break;
						}

						tmpPath = Path.Combine(destDir, new FileInfo(file).Name);
						{

							Monitor.Enter(stateLock);
							nSearchFiles++;
							Monitor.Exit(stateLock);

							FileToProcess ofile = new FileToProcess();
							ofile.fromFile = file;
							ofile.destFile = tmpPath;
							ofile.destFolder = destDir;
							ofile.fromFolder = fromDir;
							ofile.MaxThreads = this.cmdLineSettingLib.MaxThreads;
							ofile.IncludeFolders = txtIncludeFolders.Text.Trim();
							ofile.ExcludeFolders = txtExcludeFolders.Text.Trim();
							ofile.IncludeFiles = txtIncludeFiles.Text.Trim();
							ofile.ExcludeFiles = txtExcludeFiles.Text.Trim();
							
							//Monitor.Enter(fileToProcessList);
							if (ofile.CheckToProcess())
								fileToProcessList.FilesList.Add(ofile);
							//Monitor.Exit(fileToProcessList);

							if (nSearchFiles > 0 && nSearchFiles < 100)
								delFileFound.Invoke(file, nSearchFiles);

							if (nSearchFiles > 101 && nSearchFiles < 1000)
								if (nSearchFiles % 100 == 0)
									delFileFound.Invoke(file, nSearchFiles);

							if (nSearchFiles > 1001 && nSearchFiles < 10000)
								if (nSearchFiles % 250 == 0)
									delFileFound.Invoke(file, nSearchFiles);

							if (nSearchFiles > 10001)
								if (nSearchFiles % 500 == 0)
									delFileFound.Invoke(file, nSearchFiles);

						}
					}

					else
					{
						break;
					}
				}
			}

			catch (Exception ex)
			{
				//throw ex;
				Debug.WriteLine("File:" + tmpPath + " " + ex.Message);
			}
			finally
			{
				_autoEvent.Set();
			}

			nOffset -= 1;
			if (nOffset <= 0)
				if (EventSearchDone != null)
				{
					delFileFound.Invoke(null, nSearchFiles);
					EventSearchDone(this, new EventArgs());
				}
		}

		private void numUpDownThread_ValueChanged(object sender, EventArgs e)
		{
			Monitor.Enter(stateLock);
			this.cmdLineSettingLib.MaxThreads = int.Parse(numUpDownThread.Value.ToString());
			Monitor.Exit(stateLock);
			Thread.Sleep(250);

		}

		private void frmFileProcess_Load(object sender, EventArgs e)
		{


		}

		private void tsMainStartProcess_Click(object sender, EventArgs e)
		{
			this.Start();
		}

		private void tsMainStopProcess_Click(object sender, EventArgs e)
		{
			bUserStopProject = true;
			this.Stop();
		}

		private void tsMainOpenSetup_Click(object sender, EventArgs e)
		{

		}

		private void tsMainOpenAbout_Click(object sender, EventArgs e)
		{
			AboutBox f = new AboutBox();
			f.ShowDialog(this);
			
		}

		private void tsMainButtonExit_Click(object sender, EventArgs e)
		{
			this.Stop();
			Thread.Sleep(1000);
			this.Close();
		}

		private void frmFileProcess_FormClosing(object sender, FormClosingEventArgs e)
		{
			this.Stop();
		}

	}

	class DataGridViewRolloverCell : DataGridViewTextBoxCell
	{
		protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, Int32 rowIndex, DataGridViewElementStates cellState, Object value, Object formattedValue, String errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
		{
			try
			{
				base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.Message);
			}
		}
	}
}